package panels;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import panels.util.JIntegerBox;
import sprites.ActorSprite;
import sprites.ActorSprite.ActorSize;
import window.PlayerWindow;
import xml.Xml;

public class ActorPanel extends JPanel {

	/**
	 *
	 */
	private static final long serialVersionUID = 3433498385567202793L;
	public JTextField actorName;
	public JIntegerBox maxHpBox;
	public JProgressBar healthBar;
	public JIntegerBox hpBox;
	public JTabbedPane	tabPanel;
	public JIntegerBox initBox;
	public PlayerWindow playerWindow;
	private JTextPane txtNotesArea;
	private JIntegerBox conBox;
	private JIntegerBox intBox;
	private JIntegerBox strBox;
	private JIntegerBox wisBox;
	private JIntegerBox dexBox;
	private JIntegerBox chaBox;
	private JIntegerBox acBox;
	private JIntegerBox spdBox;
	private JScrollPane scrollPane;
	private ActorSprite	sprite;
	private JPanel sizePanel;
	private JComboBox<?> sizeComboBox;


	/**
	 * Create the panel.
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public ActorPanel() {

		setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
		setLayout(new BorderLayout(0, 0));

		JPanel headerPanel = new JPanel();
		add(headerPanel, BorderLayout.NORTH);

				actorName = new JTextField();
				actorName.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						getTabPanel().setTitleAt(getTabPanel().getSelectedIndex(), actorName.getText());
					}
				});
						headerPanel.setLayout(new BorderLayout(0, 0));

						headerPanel.add(actorName, BorderLayout.NORTH);
						actorName.setFont(new Font("Tahoma", Font.BOLD | Font.ITALIC, 24));
						actorName.setBackground(SystemColor.menu);
						actorName.setHorizontalAlignment(SwingConstants.CENTER);
						actorName.setColumns(10);

				JPanel statsPanel = new JPanel();
				headerPanel.add(statsPanel, BorderLayout.SOUTH);
				statsPanel.setBorder(null);
				statsPanel.setLayout(new BorderLayout(0, 0));

				JPanel abilitiesPanel = new JPanel();
				statsPanel.add(abilitiesPanel, BorderLayout.NORTH);
				abilitiesPanel.setBorder(null);
				abilitiesPanel.setLayout(new GridLayout(0, 6, 0, 0));

				strBox = new JIntegerBox((String) null, 0);
				strBox.getTextField().setFont(new Font("Dialog", Font.BOLD | Font.ITALIC, 12));
				strBox.getTextField().setText("10");
				strBox.setButtonsVisible(false);
				abilitiesPanel.add(strBox);
				strBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Str", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				dexBox = new JIntegerBox((String) null, 0);
				dexBox.getTextField().setFont(new Font("Dialog", Font.BOLD | Font.ITALIC, 12));
				dexBox.getTextField().setText("10");
				dexBox.setButtonsVisible(false);
				abilitiesPanel.add(dexBox);
				dexBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Dex", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				conBox = new JIntegerBox((String) null, 0);
				conBox.getTextField().setFont(new Font("Dialog", Font.BOLD | Font.ITALIC, 12));
				conBox.getTextField().setText("10");
				conBox.setButtonsVisible(false);
				abilitiesPanel.add(conBox);
				conBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Con", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				intBox = new JIntegerBox((String) null, 0);
				intBox.getTextField().setFont(new Font("Dialog", Font.BOLD | Font.ITALIC, 12));
				intBox.getTextField().setText("10");
				intBox.setButtonsVisible(false);
				abilitiesPanel.add(intBox);
				intBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Int", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				wisBox = new JIntegerBox((String) null, 0);
				wisBox.getTextField().setFont(new Font("Dialog", Font.BOLD | Font.ITALIC, 12));
				wisBox.getTextField().setText("10");
				wisBox.setButtonsVisible(false);
				abilitiesPanel.add(wisBox);
				wisBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Wis", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				chaBox = new JIntegerBox((String) null, 0);
				chaBox.getTextField().setFont(new Font("Dialog", Font.BOLD | Font.ITALIC, 12));
				chaBox.getTextField().setText("10");
				chaBox.setButtonsVisible(false);
				abilitiesPanel.add(chaBox);
				chaBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Cha", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				JPanel keyInfoPanel = new JPanel();
				statsPanel.add(keyInfoPanel, BorderLayout.CENTER);
				keyInfoPanel.setLayout(new GridLayout(0, 3, 0, 0));

				acBox = new JIntegerBox((String) null, 0);
				acBox.getTextField().setText("10");
				keyInfoPanel.add(acBox);
				acBox.getTextField().setFont(new Font("Arial", Font.BOLD, 27));
				acBox.setButtonsVisible(false);
				acBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Ac", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				spdBox = new JIntegerBox((String) null, 0);
				spdBox.getTextField().setText("6");
				keyInfoPanel.add(spdBox);
				spdBox.getTextField().setFont(new Font("Arial", Font.BOLD, 27));
				spdBox.setButtonsVisible(false);
				spdBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Spd", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				initBox = new JIntegerBox((String) null, 0);
				initBox.getTextField().setFont(new Font("Arial", Font.BOLD, 27));
				initBox.setButtonsVisible(false);
				initBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Init", TitledBorder.LEADING, TitledBorder.TOP, null, null));
				keyInfoPanel.add(initBox);

				JPanel healthPanel = new JPanel();
				statsPanel.add(healthPanel, BorderLayout.SOUTH);
				healthPanel.setLayout(new BorderLayout(0, 0));

				JButton addDmgButton = new JButton("+");
				addDmgButton.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						getHpBox().setValue(getHpBox().getValue() + 1);
					}
				});
				healthPanel.add(addDmgButton, BorderLayout.EAST);

				JButton removeDmgButton = new JButton("-");
				removeDmgButton.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						getHpBox().setValue(getHpBox().getValue() - 1);
					}
				});
				healthPanel.add(removeDmgButton, BorderLayout.WEST);

				healthBar = new JProgressBar();
				healthBar.setMinimum(-4);
				healthBar.setMaximum(8);
				healthBar.setValue(8);
				healthBar.setBackground(Color.BLACK);

				healthBar.addChangeListener(new ChangeListener() {
					public void stateChanged(ChangeEvent e) {
							checkHealthBar();
					}
				});
				healthPanel.add(healthBar, BorderLayout.CENTER);

				JPanel hitPointsPanel = new JPanel();
				healthPanel.add(hitPointsPanel, BorderLayout.NORTH);
				hitPointsPanel.setLayout(new GridLayout(0, 2, 0, 0));

				hpBox = new JIntegerBox((String) null, 0);
				hpBox.getTextField().setText("8");
				hitPointsPanel.add(hpBox);
				hpBox.addPropertyChangeListener(new PropertyChangeListener() {
					public void propertyChange(PropertyChangeEvent evt) {
						if (evt.getPropertyName().equals(JIntegerBox.textChanged)) {
							getHealthBar().setValue(getHpBox().getValue());
						}
					}
				});
				hpBox.getTextField().setFont(new Font("Arial", Font.BOLD, 27));
				hpBox.setButtonsVisible(false);
				hpBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Hp", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				maxHpBox = new JIntegerBox((String) null, 0);
				maxHpBox.getTextField().setText("8");
				hitPointsPanel.add(maxHpBox);
				maxHpBox.getTextField().addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						checkHealthBar();
					}
				});
				maxHpBox.setButtonsVisible(false);
				maxHpBox.getTextField().setFont(new Font("Arial", Font.BOLD, 27));
				maxHpBox.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Max Hp", TitledBorder.LEADING, TitledBorder.TOP, null, null));

				sizePanel = new JPanel();
				headerPanel.add(sizePanel, BorderLayout.CENTER);
				sizePanel.setBorder(new TitledBorder(null, "Size", TitledBorder.LEADING, TitledBorder.TOP, null, null));
				sizePanel.setLayout(new BorderLayout(0, 0));

				sizeComboBox = new JComboBox<Object>();
				sizeComboBox.setModel(new DefaultComboBoxModel(ActorSize.values()));
				sizeComboBox.setSelectedIndex(2);
				sizeComboBox.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						ActorSprite	S = getSprite();
						if (S!=null) {
							S.setSize((ActorSize) sizeComboBox.getSelectedItem());
						}
					}
				});
				sizeComboBox.setFont(new Font("Dialog", Font.BOLD | Font.ITALIC, 12));
				sizePanel.add(sizeComboBox);

		JPanel notesPanel = new JPanel();
		add(notesPanel, BorderLayout.CENTER);
		notesPanel.setBorder(new TitledBorder(null, "Notes", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		notesPanel.setLayout(new BorderLayout(0, 0));

		scrollPane = new JScrollPane();
		notesPanel.add(scrollPane, BorderLayout.CENTER);

		txtNotesArea = new JTextPane();
		txtNotesArea.setText("Melee Basic: \r\n  Str + Prof vs Ac, Wpn + Str damage\r\nRanged Basic:\r\n  Dex + Prof vs Ac, Wpn + Dex damage\r\nSpell DC:\r\n  8 + Prof + Int\r\n");
		scrollPane.setViewportView(txtNotesArea);
		checkHealthBar();

		this.setPlayerWindow(new PlayerWindow());

		setSprite(new ActorSprite(new Point(0,0), ActorSize.medium, this));

	}

	public JIntegerBox getMaxHpBox() {
		return maxHpBox;
	}
	public JProgressBar getHealthBar() {
		return healthBar;
	}
	public JIntegerBox getHpBox() {
		return hpBox;
	}
	public JTextField getActorName() {
		return actorName;
	}
	public JTabbedPane getTabPanel() {
		return tabPanel;
	}
	public void setTabPanel(JTabbedPane tabPanel) {
		this.tabPanel = tabPanel;
	}
	public JIntegerBox getInitBox() {
		return initBox;
	}

	public PlayerWindow getPlayerWindow() {
		return playerWindow;
	}

	public void setPlayerWindow(PlayerWindow playerWindow) {
		this.playerWindow = playerWindow;
	}

	public JTextPane getTxtNotesArea() {
		return txtNotesArea;
	}

	public void setCopy(ActorPanel P) {
		//
		// This will cause this actor to become a cloned duplicate of the other ActorPanell P
		//

		if (P!=null) {
			getMaxHpBox().setMaxValue(P.getMaxHpBox().getMaxValue());
			getMaxHpBox().setMinValue(P.getMaxHpBox().getMinValue());
			getMaxHpBox().setValue(P.getMaxHpBox().getValue());

			getHpBox().setMaxValue(P.getHpBox().getMaxValue());
			getHpBox().setMinValue(P.getHpBox().getMinValue());
			getHpBox().setValue(P.getHpBox().getValue());

			getHealthBar().setMaximum(P.getHealthBar().getMaximum());
			getHealthBar().setMinimum(P.getHealthBar().getMinimum());
			getHealthBar().setValue(P.getHealthBar().getValue());
			getHealthBar().setForeground(P.getHealthBar().getForeground());
			getHealthBar().setBackground(P.getHealthBar().getBackground());

			getActorName().setText(P.getActorName().getText());

			getInitBox().setValue(P.getInitBox().getValue());

			getTxtNotesArea().setText(P.getTxtNotesArea().getText());

			getSizeComboBox().setSelectedIndex(P.getSizeComboBox().getSelectedIndex());

			getConBox().setValue(P.getConBox().getValue());
			getIntBox().setValue(P.getIntBox().getValue());
			getStrBox().setValue(P.getStrBox().getValue());
			getWisBox().setValue(P.getWisBox().getValue());
			getDexBox().setValue(P.getDexBox().getValue());
			getChaBox().setValue(P.getChaBox().getValue());
			getAcBox().setValue(P.getAcBox().getValue());
			getSpdBox().setValue(P.getSpdBox().getValue());
		} else {
			System.err.println("Warning: Tried to copy from a null actor");
		}
	}

	public void checkHealthBar() {
		//
		// Check the MaxHp value anyways.
		//
		if (this.getMaxHpBox()!=null) {
			int	maxHp = getMaxHpBox().getValue();
			int bloodied = maxHp/2;
			int hp = getHpBox().getValue();
			int	mTick	= maxHp/2;

			if (hp > bloodied) {
				getHealthBar().setForeground(Color.green);
			} else if (hp > 0) {
				getHealthBar().setForeground(Color.yellow);
			} else if (hp > -maxHp/2) {
				getHealthBar().setForeground(Color.red);
			} else {
				getHealthBar().setForeground(Color.black);
			}

			getHealthBar().setValue(hp);
			getHealthBar().setMaximum(maxHp);
			getHealthBar().setMinimum(-mTick);
			getHealthBar().setValue(getHpBox().getValue());
		}
	}

	public JIntegerBox getConBox() {
		return conBox;
	}
	public JIntegerBox getIntBox() {
		return intBox;
	}
	public JIntegerBox getStrBox() {
		return strBox;
	}
	public JIntegerBox getWisBox() {
		return wisBox;
	}
	public JIntegerBox getDexBox() {
		return dexBox;
	}
	public JIntegerBox getChaBox() {
		return chaBox;
	}
	public JIntegerBox getAcBox() {
		return acBox;
	}
	public JIntegerBox getSpdBox() {
		return spdBox;
	}

	public String toXml() {
		String S = "";
		//
		// This will output the character in XML format
		//
		S += "<Actor>\n";
		S += "  <name>" + getActorName().getText()	 + "</name>\n";
		S += "  <str>" + getStrBox().getValue()			 + "</str>\n";
		S += "  <dex>" + getDexBox().getValue()			 + "</dex>\n";
		S += "  <con>" + getConBox().getValue()			 + "</con>\n";
		S += "  <int>" + getIntBox().getValue()			 + "</int>\n";
		S += "  <wis>" + getWisBox().getValue()			 + "</wis>\n";
		S += "  <cha>" + getChaBox().getValue()			 + "</cha>\n";
		S += "  <hp>" + getHpBox().getValue()			 + "</hp>\n";
		S += "  <maxHp>" + getMaxHpBox().getValue()		 + "</maxHp>\n";
		S += "  <ac>" + getAcBox().getValue()			 + "</ac>\n";
		S += "  <spd>" + getSpdBox().getValue()			 + "</spd>\n";
		S += "  <init>" + getInitBox().getValue()		 + "</init>\n";
		S += "  <notes>" + getTxtNotesArea().getText()	 + "</notes>\n";
		S += "</Actor>\n";
		return S;
	}

//	public static final String between(String source, String startToken, String endToken) {
//		//
//		// This will return the string that is Xml.between startToken and endToken. If nothing is present
//		// then an empty string is returned
//		//
//		return Xml.between(source, startToken, endToken);
//	}

	public void fromXml(String S) {
		//
		// Retrieve the elements from the xml
		//
		String nameStr	=  Xml.getTag("name", S);
		String strStr	=  Xml.getTag("str", S);
		String dexStr	=  Xml.getTag("dex", S);
		String conStr	=  Xml.getTag("con", S);
		String intStr	=  Xml.getTag("int", S);
		String wisStr	=  Xml.getTag("wis", S);
		String chaStr	=  Xml.getTag("cha", S);
		String hpStr	=  Xml.getTag("hp", S);
		String maxHpStr	=  Xml.getTag("maxHp", S);
		String acStr	=  Xml.getTag("ac", S);
		String spdStr	=  Xml.getTag("spd", S);
		String initStr	=  Xml.getTag("init", S);
		String notesStr	=  Xml.getTag("notes", S);


		//
		// Set the values parsed from the xml
		//
		this.actorName.setText(	nameStr							);
		this.strBox.setValue(		Integer.parseInt(strStr)	);
		this.dexBox.setValue(		Integer.parseInt(dexStr)	);
		this.conBox.setValue(		Integer.parseInt(conStr)	);
		this.intBox.setValue(		Integer.parseInt(intStr)	);
		this.wisBox.setValue(		Integer.parseInt(wisStr)	);
		this.chaBox.setValue(		Integer.parseInt(chaStr)	);
		this.hpBox.setValue(		Integer.parseInt(hpStr)		);
		this.maxHpBox.setValue(		Integer.parseInt(maxHpStr)	);
		this.acBox.setValue(		Integer.parseInt(acStr)		);
		this.spdBox.setValue(		Integer.parseInt(spdStr)	);
		this.initBox.setValue(		Integer.parseInt(initStr)	);
		this.txtNotesArea.setText(	notesStr					);
	}

	public void readFromFile(String filename) {
		//
		// This will read the actor information from a text file
		//
		   String content = null;
		   File file = new File(filename); //for ex foo.txt
		   try {
		       FileReader reader = new FileReader(file);
		       char[] chars = new char[(int) file.length()];
		       reader.read(chars);
		       content = new String(chars);
		       reader.close();
		   } catch (IOException e) {
		       e.printStackTrace();
		   }
		   fromXml(content);
	}

	public void writeToFile(String filename) {
		//
		// This will write the data to a file
		//
		if (filename!=null) {
			PrintWriter writer = null;
			try {
				writer = new PrintWriter(filename, "UTF-8");
				writer.println(toXml());
				writer.close();
			} catch (IOException ex) {
				System.err.println("Could not write Actor " + getActorName().getText() + " to " + filename);
			} finally {
			   try { writer.close(); } catch (Exception ex) {}
			}
		}
	}

	public ActorSprite getSprite() {
		return sprite;
	}

	public void setSprite(ActorSprite sprite) {
		ActorSprite	old = this.sprite;
		this.sprite = null;
		if (old!=null && old.getPanel() == this) {
			old.setPanel(null);
		}
		this.sprite = sprite;
		if (this.sprite != null && this.sprite.getPanel() != this) {
			this.sprite.setPanel(this);
		}
	}

	@SuppressWarnings("rawtypes")
	public JComboBox getSizeComboBox() {
		return sizeComboBox;
	}
}

